<template>
  <canvas id="com-global-clock" style="width:100%;">当前浏览器不支持canvas，请更换浏览器后再试</canvas>
</template>

<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator'

interface BallType {
  x: number
  y: number
  stepX: number
  stepY: number
  color: string
  disY: number
}

@Component({})
export default class ComGlobalClock extends Vue {
  // 高度
  @Prop({ default: 100 })
  public h!: number
  // 宽度
  @Prop({ default: 700 })
  public w!: number
  // 设置粒子半径 canvas.height / 20 - 1
  @Prop({ default: 4 })
  public r!: number

  // 点数据
  private digit = [
    [
      [0, 0, 1, 1, 1, 0, 0],
      [0, 1, 1, 0, 1, 1, 0],
      [1, 1, 0, 0, 0, 1, 1],
      [1, 1, 0, 0, 0, 1, 1],
      [1, 1, 0, 0, 0, 1, 1],
      [1, 1, 0, 0, 0, 1, 1],
      [1, 1, 0, 0, 0, 1, 1],
      [1, 1, 0, 0, 0, 1, 1],
      [0, 1, 1, 0, 1, 1, 0],
      [0, 0, 1, 1, 1, 0, 0],
    ], // 0
    [
      [0, 0, 0, 1, 1, 0, 0],
      [0, 1, 1, 1, 1, 0, 0],
      [0, 0, 0, 1, 1, 0, 0],
      [0, 0, 0, 1, 1, 0, 0],
      [0, 0, 0, 1, 1, 0, 0],
      [0, 0, 0, 1, 1, 0, 0],
      [0, 0, 0, 1, 1, 0, 0],
      [0, 0, 0, 1, 1, 0, 0],
      [0, 0, 0, 1, 1, 0, 0],
      [1, 1, 1, 1, 1, 1, 1],
    ], // 1
    [
      [0, 1, 1, 1, 1, 1, 0],
      [1, 1, 0, 0, 0, 1, 1],
      [0, 0, 0, 0, 0, 1, 1],
      [0, 0, 0, 0, 1, 1, 0],
      [0, 0, 0, 1, 1, 0, 0],
      [0, 0, 1, 1, 0, 0, 0],
      [0, 1, 1, 0, 0, 0, 0],
      [1, 1, 0, 0, 0, 0, 0],
      [1, 1, 0, 0, 0, 1, 1],
      [1, 1, 1, 1, 1, 1, 1],
    ], // 2
    [
      [1, 1, 1, 1, 1, 1, 1],
      [0, 0, 0, 0, 0, 1, 1],
      [0, 0, 0, 0, 1, 1, 0],
      [0, 0, 0, 1, 1, 0, 0],
      [0, 0, 1, 1, 1, 0, 0],
      [0, 0, 0, 0, 1, 1, 0],
      [0, 0, 0, 0, 0, 1, 1],
      [0, 0, 0, 0, 0, 1, 1],
      [1, 1, 0, 0, 0, 1, 1],
      [0, 1, 1, 1, 1, 1, 0],
    ], // 3
    [
      [0, 0, 0, 0, 1, 1, 0],
      [0, 0, 0, 1, 1, 1, 0],
      [0, 0, 1, 1, 1, 1, 0],
      [0, 1, 1, 0, 1, 1, 0],
      [1, 1, 0, 0, 1, 1, 0],
      [1, 1, 1, 1, 1, 1, 1],
      [0, 0, 0, 0, 1, 1, 0],
      [0, 0, 0, 0, 1, 1, 0],
      [0, 0, 0, 0, 1, 1, 0],
      [0, 0, 0, 1, 1, 1, 1],
    ], // 4
    [
      [1, 1, 1, 1, 1, 1, 1],
      [1, 1, 0, 0, 0, 0, 0],
      [1, 1, 0, 0, 0, 0, 0],
      [1, 1, 1, 1, 1, 1, 0],
      [0, 0, 0, 0, 0, 1, 1],
      [0, 0, 0, 0, 0, 1, 1],
      [0, 0, 0, 0, 0, 1, 1],
      [0, 0, 0, 0, 0, 1, 1],
      [1, 1, 0, 0, 0, 1, 1],
      [0, 1, 1, 1, 1, 1, 0],
    ], // 5
    [
      [0, 0, 0, 0, 1, 1, 0],
      [0, 0, 1, 1, 0, 0, 0],
      [0, 1, 1, 0, 0, 0, 0],
      [1, 1, 0, 0, 0, 0, 0],
      [1, 1, 0, 1, 1, 1, 0],
      [1, 1, 0, 0, 0, 1, 1],
      [1, 1, 0, 0, 0, 1, 1],
      [1, 1, 0, 0, 0, 1, 1],
      [1, 1, 0, 0, 0, 1, 1],
      [0, 1, 1, 1, 1, 1, 0],
    ], // 6
    [
      [1, 1, 1, 1, 1, 1, 1],
      [1, 1, 0, 0, 0, 1, 1],
      [0, 0, 0, 0, 1, 1, 0],
      [0, 0, 0, 0, 1, 1, 0],
      [0, 0, 0, 1, 1, 0, 0],
      [0, 0, 0, 1, 1, 0, 0],
      [0, 0, 1, 1, 0, 0, 0],
      [0, 0, 1, 1, 0, 0, 0],
      [0, 0, 1, 1, 0, 0, 0],
      [0, 0, 1, 1, 0, 0, 0],
    ], // 7
    [
      [0, 1, 1, 1, 1, 1, 0],
      [1, 1, 0, 0, 0, 1, 1],
      [1, 1, 0, 0, 0, 1, 1],
      [1, 1, 0, 0, 0, 1, 1],
      [0, 1, 1, 1, 1, 1, 0],
      [1, 1, 0, 0, 0, 1, 1],
      [1, 1, 0, 0, 0, 1, 1],
      [1, 1, 0, 0, 0, 1, 1],
      [1, 1, 0, 0, 0, 1, 1],
      [0, 1, 1, 1, 1, 1, 0],
    ], // 8
    [
      [0, 1, 1, 1, 1, 1, 0],
      [1, 1, 0, 0, 0, 1, 1],
      [1, 1, 0, 0, 0, 1, 1],
      [1, 1, 0, 0, 0, 1, 1],
      [0, 1, 1, 1, 0, 1, 1],
      [0, 0, 0, 0, 0, 1, 1],
      [0, 0, 0, 0, 0, 1, 1],
      [0, 0, 0, 0, 1, 1, 0],
      [0, 0, 0, 1, 1, 0, 0],
      [0, 1, 1, 0, 0, 0, 0],
    ], // 9
    [
      [0, 0, 0, 0, 0, 0, 0],
      [0, 0, 1, 1, 1, 0, 0],
      [0, 0, 1, 1, 1, 0, 0],
      [0, 0, 1, 1, 1, 0, 0],
      [0, 0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 0, 0, 0],
      [0, 0, 1, 1, 1, 0, 0],
      [0, 0, 1, 1, 1, 0, 0],
      [0, 0, 1, 1, 1, 0, 0],
      [0, 0, 0, 0, 0, 0, 0],
    ], // :
  ]
  // 时间对象
  private oTimer?: number
  // 存储时间数据
  private timeData: number[] = []
  // 存储运动的小球
  private balls: BallType[] = []

  private mounted() {
    this.creatClock()
  }

  // 创建时钟
  private creatClock() {
    const canvas: HTMLCanvasElement = document.getElementById(
      'com-global-clock',
    ) as HTMLCanvasElement
    if (canvas && canvas.getContext) {
      const cxt: CanvasRenderingContext2D = canvas.getContext(
        '2d',
      ) as CanvasRenderingContext2D
      canvas.height = this.h
      canvas.width = this.w
      cxt.fillStyle = '#f00'
      cxt.fillRect(10, 10, 50, 50)
      const temp = /(\d)(\d):(\d)(\d):(\d)(\d)/.exec(
        String(new Date()),
      ) as RegExpExecArray
      // 存储时间数字，由十位小时、个位小时、冒号、十位分钟、个位分钟、冒号、十位秒钟、个位秒钟这7个数字组成
      this.timeData.push(
        Number(temp[1]),
        Number(temp[2]),
        10,
        Number(temp[3]),
        Number(temp[4]),
        10,
        Number(temp[5]),
        Number(temp[6]),
      )

      clearInterval(this.oTimer)
      this.oTimer = setInterval(() => {
        // 更新时钟
        this.updateDigitTime()
        // 更新小球状态
        this.updateBalls()
        // 渲染
        this.canvasRender(canvas, cxt)
      }, 50)
    }
  }

  // 生成点阵数字
  private renderDigit(cxt: CanvasRenderingContext2D, index: number, num: number) {
    for (let i = 0; i < this.digit[num].length; i++) {
      for (let j = 0; j < this.digit[num][i].length; j++) {
        if (this.digit[num][i][j] === 1) {
          cxt.beginPath()
          cxt.arc(
            14 * (this.r + 2) * index + j * 2 * (this.r + 1) + (this.r + 1),
            i * 2 * (this.r + 1) + (this.r + 1),
            this.r,
            0,
            2 * Math.PI,
          )
          cxt.closePath()
          cxt.fill()
        }
      }
    }
  }

  // 渲染
  private canvasRender(canvas: HTMLCanvasElement, cxt: CanvasRenderingContext2D) {
    // 重置画布宽度，达到清空画布的效果
    canvas.height = this.h
    // 渲染时钟
    for (let i = 0; i < this.timeData.length; i++) {
      this.renderDigit(cxt, i, this.timeData[i])
    }
    // 渲染小球
    for (const item of this.balls) {
      cxt.beginPath()
      cxt.arc(item.x, item.y, this.r, 0, 2 * Math.PI)
      cxt.fillStyle = item.color
      cxt.closePath()
      cxt.fill()
    }
  }

  /*更新时钟*/
  private updateDigitTime() {
    const changeNumArray = []
    const temp = /(\d)(\d):(\d)(\d):(\d)(\d)/.exec(String(new Date()))
    const NewData = []
    NewData.push(
      Number(temp![1]),
      Number(temp![2]),
      10,
      Number(temp![3]),
      Number(temp![4]),
      10,
      Number(temp![5]),
      Number(temp![6]),
    )
    for (let i = this.timeData.length - 1; i >= 0; i--) {
      // 时间发生变化
      if (NewData[i] !== this.timeData[i]) {
        // 将变化的数字值和在data数组中的索引存储在changeNumArray数组中
        changeNumArray.push(i + '_' + ((Number(this.timeData[i]) + 1) % 10))
      }
    }
    // 增加小球
    for (const item of changeNumArray) {
      this.addBalls.apply(this, item.split('_') as any)
    }
    this.timeData = NewData.concat()
  }

  // 更新小球状态
  private updateBalls() {
    for (let i = 0; i < this.balls.length; i++) {
      this.balls[i].stepY += this.balls[i].disY
      this.balls[i].x += this.balls[i].stepX
      this.balls[i].y += this.balls[i].stepY
      if (
        this.balls[i].x > this.w + this.r ||
        this.balls[i].y > this.h + this.r
      ) {
        this.balls.splice(i, 1)
        i--
      }
    }
  }

  /*增加要运动的小球*/
  private addBalls(index: number, num: number) {
    const numArray = [1, 2, 3]
    const colorArray = [
      '#3BE',
      '#09C',
      '#A6C',
      '#93C',
      '#9C0',
      '#690',
      '#FB3',
      '#F80',
      '#F44',
      '#C00',
    ]
    for (let i = 0; i < this.digit[num].length; i++) {
      for (let j = 0; j < this.digit[num][i].length; j++) {
        if (this.digit[num][i][j] === 1) {
          const ball = {
            x: 14 * (this.r + 2) * index + j * 2 * (this.r + 1) + (this.r + 1),
            y: i * 2 * (this.r + 1) + (this.r + 1),
            stepX: Math.floor(Math.random() * 4 - 2),
            stepY: -2 * numArray[Math.floor(Math.random() * numArray.length)],
            color: colorArray[Math.floor(Math.random() * colorArray.length)],
            disY: 1,
          }
          this.balls.push(ball)
        }
      }
    }
  }

  private beforeDestroy() {
    clearInterval(this.oTimer)
  }
}

</script>

<style lang="scss" scoped>
</style>
